﻿package component.fileupload.action;

import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import component.fileupload.util.DataViewUtil;

import component.fileupload.exception.FileUploadException;
import component.fileupload.listener.FileUploadStatus;
import component.fileupload.listener.IOutputStreamListener;
import component.fileupload.service.FileUploadService;
import component.fileupload.service.IFileUploadService;
import component.fileupload.util.FileUtil;
import component.fileupload.vo.UploadFileVO;

/**
 * 文件上传的抽象类
 */
public abstract class AbstractFileUploadAction implements IFileUploadAction {
	protected Map fileInfoMap = null;
	protected IOutputStreamListener listener = null;
	protected String saveFilePath = null;

	private IFileUploadService fileUploadService = new FileUploadService();

	private String formatTime(double timeInSeconds) {
		long seconds = (long) Math.floor(timeInSeconds);
		long minutes = (long) Math.floor(timeInSeconds / 60.0);
		long hours = (long) Math.floor(minutes / 60.0);

		if (hours != 0) {
			return hours + "小时 " + (minutes % 60) + "分 " + (seconds % 60) + "秒";
		} else if (minutes % 60 != 0) {
			return (minutes % 60) + "分 " + (seconds % 60) + "秒";
		} else {
			return (seconds % 60) + " 秒";
		}
	}

	public void setParameter(Map paraMap) throws FileUploadException {

	}

	public void setSaveFilePath(String saveFilePath) {
		this.saveFilePath = saveFilePath;
	}

	public UploadFileVO[] getFileInfoArr(ServletConfig config,
			HttpServletRequest request, HttpServletResponse response)
			throws FileUploadException {
		if (fileInfoMap == null) {
			this.getInputStreams(config, request, response);
		}

		UploadFileVO[] arr = new UploadFileVO[fileInfoMap.size()];
		for (int i = 0; i < fileInfoMap.size(); i++) {
			UploadFileVO vo = (UploadFileVO) fileInfoMap.get(new Integer(i));
			arr[i] = vo;
		}
		return arr;
	}
	
	public String doUploadToOther(ServletConfig config, HttpServletRequest request, HttpServletResponse response) throws FileUploadException {
		InputStream is = this.getInputStreams(config, request, response)[0];
		try {
			String action = request.getParameter("action");
			String operate = request.getParameter("operate");
			
			Class<?> actionCl = Class.forName(action);
			Object actionObj = actionCl.newInstance();
			
			Method method = actionCl.getMethod(operate, new Class[]{InputStream.class,HttpServletRequest.class});
			Object retObj = method.invoke(actionObj, new Object[]{is,request});
			return (String)retObj;
			
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return null;
	}

	public String doUpload(ServletConfig config, HttpServletRequest request,
			HttpServletResponse response) throws FileUploadException {
		HttpSession session = request.getSession();
		String isUpload = "true";

		if (fileInfoMap == null) {
			this.getInputStreams(config, request, response);
		}
		String realPath = request.getRealPath("/");
		System.out.println("服务器的相对路径 = " + realPath);

		// 获取相对路径
		if(saveFilePath == null) {
			saveFilePath = request.getParameter("saveFilePath");
		}
		String relativePath = saveFilePath == null ? FileUtil
				.getRelativePath(null) : saveFilePath;

		try {
			fileUploadService.saveFiles(realPath, relativePath, fileInfoMap);
		} catch (FileUploadException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			isUpload = "false";
			listener.error(e.getMessage());
			throw new FileUploadException(e);
		}
		request.getSession().setAttribute("fileInfoMap", fileInfoMap);

		// 停止使用监听器
		listener.done();
		System.out.println("停止监听");

		return isUpload;
	}
	
	public String receiveFile(HttpServletRequest request, HttpServletResponse response, String fileName) throws FileUploadException {
		String realPath = request.getRealPath("/");
		System.out.println("服务器的相对路径 = " + realPath);

		// 获取相对路径
		String relativePath = saveFilePath == null ? FileUtil
				.getRelativePath(null) : saveFilePath;

		String serverSaveFilePath = FileUtil.changeSlash(realPath)
				+ relativePath + FileUtil.getFileSeparator() + fileName;

		InputStream in = null;
		OutputStream out = null;
		ServletOutputStream servletout = null;
		try {
			in = request.getInputStream();
			out = new FileOutputStream(new File(serverSaveFilePath));
			byte[] buf = new byte[1024];
			int readed = 0;
			while ((readed = in.read(buf)) != -1) {
				out.write(buf, 0, readed);
			}
			out.flush();

			// 返回数据
			byte retBuf[] = component.fileupload.util.DataViewUtil
					.writeObject("上传成功！");
			servletout = response.getOutputStream();
			servletout.write(retBuf);

		} catch (IOException e) {
			e.printStackTrace();
			throw new FileUploadException(e);
		} finally {
			try {
				if (in != null)
					in.close();
				if (out != null)
					out.close();
				if (servletout != null)
					servletout.close();
			} catch (IOException e) {
				e.printStackTrace();
				throw new FileUploadException(e);
			}
		}
		return "true";
	}
	
	public Object sendFile(String localFile, String httpUrl, String method, String saveFileName, String parameters) throws FileUploadException {
		String httpUrl_ = httpUrl + "?action=" + method + "&saveFileName=" + saveFileName;
		if(parameters != null && !"".equals(parameters)){
			httpUrl_ += parameters;
		}
		
		OutputStream os = null;
		InputStream is = null;
		try {
			URL url = new URL(httpUrl_);

			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("POST");
			conn.setDoOutput(true);
			conn.setDoInput(true);

			conn.setRequestProperty("Content-Type", "multipart/form-data;");// 设置表单类型
			// conn.setRequestProperty("Content-type", "application/octest-stream");
			// conn.setRequestProperty("Content-Length", ); //设置内容长度

			os = conn.getOutputStream();

			FileInputStream fis = new FileInputStream(new File(localFile)); // 要上传的文件

			int len;
			byte[] buf = new byte[1024];
			while ((len = fis.read(buf, 0, 1024)) > 0) {
				os.write(buf, 0, len);

			}
			os.flush();
			fis.close();

			// 得到返回的信息
//			is = conn.getInputStream();
//			byte[] inbuf = new byte[1024];
//			int rn;
//			while ((rn = is.read(inbuf, 0, 1024)) > 0) {
//				System.out.write(inbuf, 0, rn);
//			}
			is = new DataInputStream(conn.getInputStream());
			Object retObj = DataViewUtil.readObject(is);
			return retObj;
			
		} catch (IOException e) {
			e.printStackTrace();
			throw new FileUploadException(e);
		} finally {
			try {
				if (os != null)
					os.close();
				if (is != null)
					is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public String[] getFilePaths() {
		// TODO Auto-generated method stub
		String[] filePathArr = new String[fileInfoMap.size()];
		for (int i = 0; i < fileInfoMap.size(); i++) {
			UploadFileVO vo = (UploadFileVO) fileInfoMap.get(new Integer(i));
			filePathArr[i] = vo.getDbSaveFilePath();
		}
		return filePathArr;
	}

	public Map getFileInfos() {
		return fileInfoMap;
	}

	public String getState(HttpSession session, HttpServletResponse response)
			throws IOException {
		// 设置该响应不在缓存中读取
		response.addHeader("Expires", "0");
		response.addHeader("Cache-Control",
				"no-store, no-cache, must-revalidate");
		response.addHeader("Cache-Control", "post-check=0, pre-check=0");
		response.addHeader("Pragma", "no-cache");
		response.setContentType("text/html;charset=GBK");

		// 获得保存在Session中的状态信息
		FileUploadStatus fileUploadStats = (FileUploadStatus) session
				.getAttribute("FILE_UPLOAD_STATS");
		Map fileInfoMap = (Map)session.getAttribute("fileInfoMap");
		if (fileUploadStats == null && fileInfoMap == null)
			return "";
		
		String stateStr = "<b>上传状态:</b><br/>";
		if(fileInfoMap != null) {
			//传回保存路径
			UploadFileVO vo = (UploadFileVO)fileInfoMap.get(new Integer(0));
			stateStr += "saveFilePath:" + vo.getDbSaveFilePath() ;
			stateStr += ",complete";
			
			session.setAttribute("fileInfoMap", null);
			
			// 将上传状态返回给客户端
			response.getWriter().println(stateStr);

			return stateStr;
		}

		long bytesProcessed = fileUploadStats.getBytesRead();// 获得已经上传的数据大小
		long sizeTotal = fileUploadStats.getTotalSize();// 获得上传文件的总大小

		// 如果文件已经上传完毕
		if (FileUploadStatus.completeStatus.equals(fileUploadStats.getCurrentStatus()) || fileInfoMap != null || fileUploadStats.getBytesRead() == fileUploadStats.getTotalSize()) {
			// if (fileUploadStats != null &&
			// fileUploadStats.getCurrentStatus().equals("done")) {
			stateStr += "上传: 上传" + (bytesProcessed / 1024) + "KB 共 "
					+ (sizeTotal / 1024) + " KB <br/>";

			//传回保存路径
			UploadFileVO vo = (UploadFileVO)fileInfoMap.get(new Integer(0));
			stateStr += "saveFilePath:" + vo.getDbSaveFilePath() ;
			stateStr += ",complete";
			
			session.setAttribute("fileInfoMap", null);
		} else if (fileUploadStats.getCurrentStatus().equals("error")) {
			stateStr += "上传出错";
			stateStr += "error";
		} else {
			// 计算上传完成的百分比
			long percentComplete = (long) Math
					.floor(((double) bytesProcessed / (double) sizeTotal) * 100.0);
			// 获得上传已用的时间
			long timeInSeconds = fileUploadStats.getElapsedTimeInSeconds();
			// 计算平均上传速率
			double uploadRate = bytesProcessed / (timeInSeconds + 0.00001);
			// 计算总共所需时间
			double estimatedRuntime = sizeTotal / (uploadRate + 0.00001);

			if (fileUploadStats.getBytesRead() != fileUploadStats
					.getTotalSize()) {
				stateStr += "<div class=\"prog-border\"><div class=\"prog-bar\" style=\"width: "
						+ percentComplete + "%;\"></div></div>";

				stateStr += "上传进度:已上传" + (bytesProcessed / 1024) + "KB " + "总共"
						+ (sizeTotal / 1024) + " KB " + "完成(" + percentComplete
						+ "%) " + (long) Math.round(uploadRate / 1024)
						+ " Kb/s <br/>";

				stateStr += "运行&nbsp;&nbsp;&nbsp;&nbsp;:已运行"
						+ formatTime(timeInSeconds) + " 共需 "
						+ formatTime(estimatedRuntime) + "　剩余 "
						+ formatTime(estimatedRuntime - timeInSeconds)
						+ "  <br/>";
			}
		}

		System.out.println(stateStr);

		// 将上传状态返回给客户端
		response.getWriter().println(stateStr);

		return stateStr;
	}

	public String doDelete(ServletContext servletContext, String filePath)
			throws FileUploadException {
		filePath = FileUtil.changeSlash(filePath);

		String realPath = servletContext.getRealPath("");
		realPath = FileUtil.changeSlash(realPath);

		FileUtil.deleteFile(realPath + filePath);

		return "true";
	}
}
